package jnpf.database.util;

import com.alibaba.fastjson.JSONObject;
import jnpf.config.ConfigValueUtil;
import jnpf.constant.MsgCode;
import jnpf.database.enums.TenantDbSchema;
import jnpf.database.model.TenantVO;
import jnpf.exception.LoginException;
import jnpf.util.JsonUtil;
import jnpf.util.TenantProvider;
import jnpf.util.data.DataSourceContextHolder;
import jnpf.util.wxutil.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.Map;

/**
 * @author JNPF开发平台组
 * @user N
 * @copyright 引迈信息技术有限公司
 * @date 2022/10/13 16:16
 */
@Slf4j
@Component
public class TenantDataSourceUtil {

    private static ConfigValueUtil configValueUtil;

    @Autowired
    public void setConfigValueUtil(ConfigValueUtil configValueUtil) {
        TenantDataSourceUtil.configValueUtil = configValueUtil;
    }

    public static final String DBLINK_KEY = "TenantInfo";

    /**
     * 设置租户信息到Redis缓存中
     * @param tenantId
     * @param tenant
     */
    public static void setTenantInfo(String tenantId, TenantVO tenant) {
        TenantProvider.putTenantCache(tenantId, DBLINK_KEY, tenant);
    }

    /**
     * 从Redis缓存中获取租户信息
     * @param tenantId
     * @return
     */
    public static TenantVO getTenantInfo(String tenantId){
        return TenantProvider.getTenantCache(tenantId, DBLINK_KEY);
    }


    /**
     * 从租户系统获取租户信息
     * @param tenantId
     * @return
     * @throws LoginException
     */
    public static TenantVO getRemoteTenantInfo(String tenantId) throws LoginException {
        JSONObject object = HttpUtil.httpRequest(configValueUtil.getMultiTenancyUrl() + tenantId, "GET", null);
        if (object == null || "500".equals(object.get("code").toString())) {
            throw new LoginException(MsgCode.LOG105.get());
        }
        if ("400".equals(object.getString("code"))) {
            log.error("获取多租户信息失败：{}", object.getString("msg"));
            if (configValueUtil.getMultiTenancyUrl().contains("https")) {
                throw new LoginException(object.getString("msg"));
            } else {
                throw new LoginException(object.getString("msg"));
            }
        }
        Map<String, Object> resulList  = JsonUtil.stringToMap(object.getString("data"));
        // 租户库名
        TenantVO vo;
        if (resulList.get("java") != null) {
            vo = new TenantVO().setDataSchema(TenantDbSchema.DEFAULT).setDbName(String.valueOf(resulList.get("java")));
        } else {
            // 转换成租户信息模型
            vo = JsonUtil.getJsonToBean(resulList, TenantVO.class);
            if(ObjectUtils.isEmpty(vo.getLinkList())){
                vo.setDataSchema(TenantDbSchema.DEFAULT);
                vo.setLinkList(null);
            }else {
                vo.setDataSchema(TenantDbSchema.REMOTE);
            }
            TenantDataSourceUtil.setTenantInfo(tenantId, vo);
        }
        return vo;
    }

    /**
     * 切换租户， 先从Redis缓存中获取， 在从租户系统中获取
     * @param tenantId
     */
    public static void switchTenant(String tenantId) throws LoginException {
        TenantVO tenantVO = TenantDataSourceUtil.getTenantInfo(tenantId);
        if(tenantVO == null){
            tenantVO = TenantDataSourceUtil.getRemoteTenantInfo(tenantId);
        }
        switchTenant(tenantId, tenantVO);
    }


    /**
     * 切换租户
     */
    public static void switchTenant(String tenantId, TenantVO tenantVO) throws LoginException {
        Assert.notNull(tenantVO, "租户信息获取失败");
        if(tenantVO != null){
            String dbName;
            switch (tenantVO.getDataSchema()){
                case REMOTE:
                    dbName = "true";
                    break;
                case DEFAULT:
                    dbName = tenantVO.getDbName();
                    break;
                default:
                    throw new LoginException(MsgCode.LOG102.get());
            }
            DataSourceContextHolder.setDatasource(tenantId, dbName);
        }
    }


}
